package api

import (
	"context"
	"errors"
	"time"

	"github.com/gin-gonic/gin"
	"zhonghui/console/service"
	"zhonghui/console/structs"
	"zhonghui/console/warehouse/dbx/db_zh_kernel"
	"zhonghui/console/warehouse/dbx/db_zh_kernel_slave"
	"zhonghui/console/warehouse/helperx"
	"zhonghui/console/warehouse/logx"
	"zhonghui/console/warehouse/modelx/model_zh_kernel"
	"zhonghui/console/warehouse/respx"
)

func (server *Server) GetTaskList(c *gin.Context) {
	req := structs.GetTaskListReq{}
	_ = c.ShouldBindQuery(&req)

	tasks := make([]model_zh_kernel.SysTask, 0)
	query := db_zh_kernel.ClientCtx(c).Model(model_zh_kernel.SysTask{})

	page, size := helperx.ParseNormalPager(req.NormalPagerReq)

	if req.State != "" {
		query = query.Where("status = ?", req.State)
	}

	var total int64
	query.Count(&total)

	query.Order("id desc").
		Offset((page - 1) * size).
		Limit(size).
		Find(&tasks)

	resp := make([]structs.GetTaskListResp, 0)
	for _, task := range tasks {
		// 临时的进度数据
		tmpProgress := service.GetTaskTempProgress(task.ID)
		tmpProgressFail := service.GetTaskTempProgressFail(task.ID)

		// 模板消息
		tp := model_zh_kernel.SysSmsTemplate{}
		db_zh_kernel_slave.Client().Where("template_id = ?", task.SmsTemplate).Take(&tp)

		tmp := structs.GetTaskListResp{
			ID:              task.ID,
			Title:           task.Title,
			State:           task.Status,
			Remark:          task.Remark,
			ConfigID:        task.ConfigID,
			Count:           task.Count,
			CountSuccess:    task.CountSuccess,
			CountFail:       task.CountFail,
			TemplateID:      tp.TemplateID,
			TemplateContent: tp.Content,
			CreatedAt:       task.CreateTime.Format(helperx.TimeLayoutCommon),
		}

		if task.Status == "completed" {
			tmp.UpdatedAt = task.UpdateTime.Format(helperx.TimeLayoutCommon)
		}

		if task.Status == structs.TaskStatusProcessing || task.Status == structs.TaskStatusPaused {
			tmp.CountSuccess = tmpProgress
			tmp.CountFail = tmpProgressFail
		} else {
			tmp.CountSuccess = task.CountSuccess
			tmp.CountFail = task.CountFail
		}
		// 进度
		tmp.Progress = uint64((float64(tmp.CountSuccess+tmp.CountFail) / float64(task.Count)) * 100)

		resp = append(resp, tmp)
	}

	respx.Success(c, resp, helperx.MakeNormalPagerResp(total, size))
}

func (server *Server) CreateTask(c *gin.Context) {
	req := structs.CreateTaskRequest{}
	if err := c.ShouldBindJSON(&req); err != nil {
		respx.Bad(c, err)
		return
	}

	contact, err := server.store.GetContactListByConfigID(context.Background(), req.ConfigID)
	if err != nil {
		logx.Zap().Errorw("创建任务失败", "err", err)
		respx.Alert(c, "创建失败，请重试")
		return
	}

	if contact.ConfigID != req.ConfigID {
		logx.Zap().Errorw("创建任务失败，配置id不一致")
		respx.Alert(c, "创建失败，请重试")
		return
	}

	// 模板消息
	tp := model_zh_kernel.SysSmsTemplate{}
	if db_zh_kernel_slave.Client().Where("template_id = ?", req.TemplateID).Take(&tp).Error != nil {
		respx.Alert(c, "创建失败，请重试")
		return
	}

	newTask := model_zh_kernel.SysTask{
		Title:       req.Title,
		Channel:     "zhonghui",
		Status:      structs.TaskStatusCreated,
		Source:      req.Source,
		Remark:      req.Remark,
		ConfigID:    contact.ConfigID,
		SmsTemplate: tp.TemplateID,
	}
	if service.HasDwz(tp.Content) {
		newTask.UseDwz = 1
	}
	if err := db_zh_kernel.ClientCtx(c).Save(&newTask).Error; err != nil {
		logx.Zap().Errorw("创建任务失败", "err", err)
		respx.Alert(c, "创建失败，请重试")
		return
	}

	time.Sleep(1 * time.Second)

	if err := service.TriggerFileParseTask(newTask.ID); err != nil {
		logx.Zap().Errorw("发送任务文件解析失败", "err", err)
	}

	respx.Success(c, nil, nil)
}

func (server *Server) StartTask(c *gin.Context) {
	task := model_zh_kernel.SysTask{}
	if err := db_zh_kernel.ClientCtx(c).Where("id = ?", c.Param("id")).Take(&task).Error; err != nil {
		respx.Alert(c, "无法找到该任务")
		return
	}

	if task.Status != structs.TaskStatusPrepared {
		respx.Alert(c, "当前状态无法开始")
		return
	}

	if !service.IsSafeTimeForTask() {
		respx.Alert(c, "当前时间不可发送任务")
		return
	}

	up := db_zh_kernel.ClientCtx(c).Model(model_zh_kernel.SysTask{}).Where("id = ? and status = ?", task.ID, task.Status).Updates(map[string]interface{}{
		"status": structs.TaskStatusProcessing,
	})
	if up.Error != nil {
		respx.Error(c, "操作失败", up.Error)
		return
	}
	if up.RowsAffected != 1 {
		respx.Error(c, "操作失败", errors.New("affect row not one"))
		return
	}

	respx.Success(c, nil, nil)
}

func (server *Server) PauseTask(c *gin.Context) {
	task := model_zh_kernel.SysTask{}
	if err := db_zh_kernel.ClientCtx(c).Where("id = ?", c.Param("id")).Take(&task).Error; err != nil {
		respx.Alert(c, "无法找到该任务")
		return
	}

	if task.Status != structs.TaskStatusProcessing {
		respx.Alert(c, "当前状态无法暂停")
		return
	}

	up := db_zh_kernel.ClientCtx(c).Model(model_zh_kernel.SysTask{}).Where("id = ? and status = ?", task.ID, task.Status).Updates(map[string]interface{}{
		"status": structs.TaskStatusPaused,
	})
	if up.Error != nil {
		respx.Error(c, "操作失败", up.Error)
		return
	}
	if up.RowsAffected != 1 {
		respx.Error(c, "操作失败", errors.New("affect row not one"))
		return
	}

	respx.Success(c, nil, nil)
}

func (server *Server) UnPauseTask(c *gin.Context) {
	task := model_zh_kernel.SysTask{}
	if err := db_zh_kernel.ClientCtx(c).Where("id = ?", c.Param("id")).Take(&task).Error; err != nil {
		respx.Alert(c, "无法找到该任务")
		return
	}

	if task.Status != structs.TaskStatusPaused {
		respx.Alert(c, "当前状态无法开始")
		return
	}

	if !service.IsSafeTimeForTask() {
		respx.Alert(c, "当前时间不可发送任务")
		return
	}

	up := db_zh_kernel.ClientCtx(c).Model(model_zh_kernel.SysTask{}).Where("id = ? and status = ?", task.ID, task.Status).Updates(map[string]interface{}{
		"status": structs.TaskStatusProcessing,
	})
	if up.Error != nil {
		respx.Error(c, "操作失败", up.Error)
		return
	}
	if up.RowsAffected != 1 {
		respx.Error(c, "操作失败", errors.New("affect row not one"))
		return
	}

	respx.Success(c, nil, nil)
}

func (server *Server) StopTask(c *gin.Context) {
	task := model_zh_kernel.SysTask{}
	if err := db_zh_kernel.ClientCtx(c).Where("id = ?", c.Param("id")).Take(&task).Error; err != nil {
		respx.Error(c, "无法找到该任务", err)
		return
	}

	switch task.Status {
	case structs.TaskStatusPaused, structs.TaskStatusCreated, structs.TaskStatusPrepared:
	default:
		respx.Alert(c, "当前状态无法删除")
		return
	}

	// 先停止
	db_zh_kernel.ClientCtx(c).Model(model_zh_kernel.SysTask{}).Where("id = ? and status = ?", task.ID, task.Status).Updates(map[string]interface{}{
		"status": structs.TaskStatusStopped,
	})
	// 睡一下，等待任务结束
	time.Sleep(500 * time.Millisecond)

	// 开始强制停止
	// 汇总统计
	type result struct {
		Total  int64
		Status string
	}
	res := make([]result, 0)
	db_zh_kernel_slave.Client().Model(&model_zh_kernel.SysSmsRecord{}).
		Where("task_id = ?", task.ID).
		Group("status").
		Select("count(1) as total, status").
		Find(&res)

	var total, success, fail uint64
	for _, r := range res {
		switch r.Status {
		case "":
		case "queue", "prepared":
		case "fail":
			fail++
		default:
			success++
		}

		total++
	}

	db_zh_kernel.ClientCtx(c).Model(model_zh_kernel.SysTask{}).Where("id = ? and status = ?", structs.TaskStatusStopped).Updates(map[string]interface{}{
		"count_success": success,
		"count_fail":    fail,
	})

	respx.Success(c, nil, nil)
}

func (server *Server) TestTask(c *gin.Context) {
	req := structs.TestTaskReq{}
	if err := c.ShouldBindJSON(&req); err != nil {
		respx.Bad(c, err)
		return
	}

	if !helperx.IsPhone(req.Phone) {
		respx.Alert(c, "手机号码格式不正确")
		return
	}

	// 查询任务
	task := model_zh_kernel.SysTask{}
	if err := db_zh_kernel.ClientCtx(c).Where("id = ?", c.Param("id")).Take(&task).Error; err != nil {
		respx.Error(c, "无法找到该任务", err)
		return
	}
	switch task.Status {
	case structs.TaskStatusPrepared:
	default:
		respx.Alert(c, "当前状态无法测试")
		return
	}

	// 随机取一个record
	record := model_zh_kernel.SysSmsRecord{}
	if err := db_zh_kernel.ClientCtx(c).Where("task_id = ?", task.ID).Take(&record).Error; err != nil {
		respx.Error(c, "无法找到该任务的记录", err)
		return
	}

	// 初始化返回
	resp := structs.TestTaskResp{
		Phone: req.Phone,
	}

	// 生成短网址
	localDwz := service.GenLocalSmsUrl(record.ID, req.Phone, "p1")
	dwz := service.GenBaiduDwzBatch([]string{localDwz})
	resp.Dwz = dwz[0].ShortUrl

	// 解析短信模板参数
	params := service.ParseRecordParamsForSms(&record)

	// 发送短信
	err := service.SendSms(req.Phone, params, false, task.SmsTemplate)
	if err != nil {
		resp.SmsResult = "失败-" + err.Error()
	} else {
		resp.SmsResult = "成功"
	}

	respx.Success(c, resp, nil)
}

func (server *Server) SmsTemplate(c *gin.Context) {
	list := make([]model_zh_kernel.SysSmsTemplate, 0)
	db_zh_kernel.ClientCtx(c).Find(&list)

	resp := make([]structs.SmsTemplateResp, 0)
	for _, item := range list {
		resp = append(resp, structs.SmsTemplateResp{
			Name:       item.Content,
			TemplateID: item.TemplateID,
		})
	}

	respx.Success(c, resp, nil)
}
